package youfu

import (
	"bytes"
	"crypto"
	"crypto/des"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"strings"
)

const (
	kPublicKeyPrefix = "-----BEGIN PUBLIC KEY-----"
	kPublicKeySuffix = "-----END PUBLIC KEY-----"

	kPKCS1Prefix = "-----BEGIN RSA PRIVATE KEY-----"
	KPKCS1Suffix = "-----END RSA PRIVATE KEY-----"

	kPKCS8Prefix = "-----BEGIN PRIVATE KEY-----"
	KPKCS8Suffix = "-----END PRIVATE KEY-----"

	kPublicKeyType     = "PUBLIC KEY"
	kPrivateKeyType    = "PRIVATE KEY"
	kRSAPrivateKeyType = "RSA PRIVATE KEY"
)

// base64 加密
func base64Encode(data []byte) string {
	return base64.StdEncoding.EncodeToString(data)
}

// base64 解密
func base64Decode(data string) ([]byte, error) {
	return base64.StdEncoding.DecodeString(data)
}

func jsonMarshal(v interface{}) string {
	if v == nil {
		return ""
	}
	if r, err := json.Marshal(v); err != nil {
		return ""
	} else {
		return string(r)
	}
}

func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}

func PKCS5UnPadding(origData []byte) []byte {
	length := len(origData)
	// 去掉最后一个字节 unpadding 次
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

func DesECBEntrypt(data, key []byte) []byte {
	if len(key) > 0 {
		key = key[:]
	}
	block, err := des.NewCipher(key)
	if err != nil {
		fmt.Printf("EntryptDesECB newCipher error[%v]", err)
		return []byte("")
	}
	bs := block.BlockSize()
	data = PKCS5Padding(data, bs)
	if len(data)%bs != 0 {
		fmt.Printf("EntryptDesECB Need a multiple of the blocksize")
		return []byte("")
	}
	out := make([]byte, len(data))
	dst := out
	for len(data) > 0 {
		block.Encrypt(dst, data[:bs])
		data = data[bs:]
		dst = dst[bs:]
	}
	return out
}

func DESECBDecrypt(data, key []byte) (string, error) {
	if len(key) > 0 {
		key = key[:]
	}
	block, err := des.NewCipher(key)
	if err != nil {
		return "", fmt.Errorf("DecryptDES NewCipher error[%v]", err)
	}
	bs := block.BlockSize()
	if len(data)%bs != 0 {
		return "", fmt.Errorf("DecryptDES crypto/cipher: input not full blocks")
	}
	out := make([]byte, len(data))
	dst := out
	for len(data) > 0 {
		block.Decrypt(dst, data[:bs])
		data = data[bs:]
		dst = dst[bs:]
	}
	out = PKCS5UnPadding(out)
	return string(out), nil
}

// 对数据进行数字签名
func getRSASign(data string, privateKey *rsa.PrivateKey) (string, error) {
	// 计算Sha1散列值
	hash := sha1.New()
	hash.Write([]byte(data))
	sum := hash.Sum(nil)
	// 从1.5版本规定，使用RSASSA-PKCS1-V1_5-SIGN 方案计算签名
	signPKCS1v15, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA1, sum)

	return string(signPKCS1v15), err
}

// 验证签名
func verifyRsaSign(data string, publicKey *rsa.PublicKey, sign string) error {
	// 计算Sha1散列值
	base64Sign, _ := base64Decode(sign)
	hash := crypto.SHA1.New()
	hash.Write([]byte(data))
	bytes := hash.Sum(nil)
	return rsa.VerifyPKCS1v15(publicKey, crypto.SHA1, bytes, base64Sign)
}

func formatKey(raw, prefix, suffix string, lineCount int) []byte {
	if raw == "" {
		return nil
	}
	raw = strings.Replace(raw, prefix, "", 1)
	raw = strings.Replace(raw, suffix, "", 1)
	raw = strings.Replace(raw, " ", "", -1)
	raw = strings.Replace(raw, "\n", "", -1)
	raw = strings.Replace(raw, "\r", "", -1)
	raw = strings.Replace(raw, "\t", "", -1)

	var sl = len(raw)
	var c = sl / lineCount
	if sl%lineCount > 0 {
		c = c + 1
	}

	var buf bytes.Buffer
	buf.WriteString(prefix + "\n")
	for i := 0; i < c; i++ {
		var b = i * lineCount
		var e = b + lineCount
		if e > sl {
			buf.WriteString(raw[b:])
		} else {
			buf.WriteString(raw[b:e])
		}
		buf.WriteString("\n")
	}
	buf.WriteString(suffix)
	return buf.Bytes()
}

func ParsePKCS8PrivateKey(privateKey string) (key *rsa.PrivateKey) {
	privateKey = strings.Replace(privateKey, kPKCS1Prefix, "", 1)
	privateKey = strings.Replace(privateKey, KPKCS1Suffix, "", 1)
	data := formatKey(privateKey, kPKCS8Prefix, KPKCS8Suffix, 64)
	var block *pem.Block
	block, _ = pem.Decode(data)
	if block == nil {
		return nil
	}
	rawKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		fmt.Printf("私钥加载失败: %s\n\n", err.Error())
		return nil
	}
	key, ok := rawKey.(*rsa.PrivateKey)
	if ok == false {
		return nil
	}

	return key
}
func ParsePublicKey(publickey string) (key *rsa.PublicKey) {
	data := formatKey(publickey, kPublicKeyPrefix, kPublicKeySuffix, 64)
	var block *pem.Block
	block, _ = pem.Decode(data)
	if block == nil {
		return nil
	}

	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil
	}
	key, ok := pubInterface.(*rsa.PublicKey)
	if !ok {
		return nil
	}
	return key
}

func ReadFile(file string) ([]byte, error) {
	f, err := ioutil.ReadFile(file)
	if err != nil {
		fmt.Println("read fail", err)
		return nil, err
	}
	return f, nil
}
